package com.test.config;

import com.test.entity.RestBean;
import com.test.entity.dto.Account;
import com.test.entity.vo.response.AuthorizeVo;
import com.test.filter.JwtAuthenticationFilter;
import com.test.service.AccountService;
import com.test.utils.JwtUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.IOException;

@Configuration
public class SecurityConfiguration {
    @Resource
    JwtAuthenticationFilter filter;
    @Resource
    JwtUtils utils;
    @Resource
    AccountService service;
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                .authorizeHttpRequests(conf ->{
                    conf.requestMatchers("images/**").permitAll();
                    conf.requestMatchers("/api/auth/**","/error").permitAll();
                    conf.anyRequest().authenticated();
                })
                .formLogin(conf ->{
                    conf.loginProcessingUrl("/api/auth/login");
                    conf.successHandler(this::onAuthenticationSuccess);
                    conf.failureHandler(this::onAuthenticationFailure);


                    })
                .logout(conf ->{
                    conf.logoutUrl("/api/auth/logout");
                    conf.logoutSuccessHandler(this::onLogoutSuccess);
                })
                .csrf(AbstractHttpConfigurer::disable)

                .sessionManagement(conf ->{
                    conf.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
                })
                .exceptionHandling(conf ->{
                    //jwt验证失败的处理
                    conf.authenticationEntryPoint(this::handleProcess);
                    //验证成功，但是权限
                    conf.accessDeniedHandler(this::accessProcess);
                })
                .addFilterBefore( filter, UsernamePasswordAuthenticationFilter.class)

                .build();
    }



    void accessProcess(HttpServletRequest request,
                       HttpServletResponse response,
                       AccessDeniedException exception)throws IOException{
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        response.getWriter().write(RestBean.failure(403,exception.getMessage()).asJsonString());
    }

    void handleProcess(HttpServletRequest request,
                       HttpServletResponse response,
                       AuthenticationException exception)throws IOException{
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        response.getWriter().write(RestBean.failure(401,exception.getMessage()).asJsonString());
    }
    void onAuthenticationSuccess(HttpServletRequest request,
                                 HttpServletResponse response,
                                 Authentication authentication) throws IOException ,ServletException{
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        User user = (User) authentication.getPrincipal();
        Account account = service.findByUsername(user.getUsername());
        String token = utils.createJwt(user, account.getId(),account.getUsername());
        AuthorizeVo vo = new AuthorizeVo();
        vo.setRole(account.getRole());
        vo.setId(account.getId());
        vo.setName(user.getUsername());
        vo.setToken(token);
        vo.setExpire(utils.expireTime());
        response.getWriter().write(RestBean.success(vo).asJsonString());

    }
    void onAuthenticationFailure(HttpServletRequest request,
                                 HttpServletResponse response,
                                 AuthenticationException exception) throws IOException, ServletException {
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        System.out.println("进入错误");
        System.out.println(exception.getMessage());

        response.getWriter().write(RestBean.failure(401,exception.getMessage()).asJsonString());

    }


    /**
     * 当用户成功注销时调用的方法
     *
     * @param request HttpServletRequest对象，用于获取请求信息
     * @param response HttpServletResponse对象，用于向客户端发送响应
     * @param authentication Authentication对象，包含用户认证信息
     * @throws IOException 如果在发送响应时发生I/O错误
     * @throws ServletException 如果在处理过程中发生Servlet相关的错误
     */
    void onLogoutSuccess(HttpServletRequest request,
                         HttpServletResponse response,
                         Authentication authentication) throws IOException ,ServletException{
        // 设置响应内容类型为JSON，字符编码为UTF-8
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");

        // 检查Authorization头是否有效
        if(utils.inValidated(request.getHeader("Authorization")))
            // 如果无效，向客户端发送注销成功的JSON响应
            response.getWriter().write(RestBean.success("注销成功").asJsonString());
        else {
            // 如果有效，向客户端发送注销失败的JSON响应
            response.getWriter().write(RestBean.failure(400,"注销失败").asJsonString());
        }
    }



}
